//
// Created by tianq on 25-5-3.
// The shape application. Initially we need only squares and circles. Provide this solution.
//

#include <iostream>
#include <memory>
#include <vector>
#include <SFML/Graphics.hpp>
using namespace std;

class Shape {
protected:
    sf::Vector2f position{0,0};
    float rotation = 0.0f;       // in degrees

public:
    virtual ~Shape() = default;

    void setPosition(const sf::Vector2f pos) { position = pos; }
    void setPosition(const float x, const float y) { position = {x, y}; }
    void setRotation(const float degrees) { rotation = degrees; }

    // unified render entry
    std::unique_ptr<sf::Shape> render() {
        auto shape = draw();      // draw implemented by subclasses
        applyTransform(shape);    // apply transform
        return shape;
    }

private:
    // transform performed by base class,
    // subclasses should not mess with it, hence private here
    void applyTransform(const std::unique_ptr<sf::Shape>& shape) const {
        shape->setPosition(position);
        shape->setRotation(sf::degrees(rotation));
    }

    virtual std::unique_ptr<sf::Shape> draw() = 0;
};

class Circle final : public Shape {
    float radius{};

public:
    explicit Circle(const float radius = 1.0f) {
        cout << "Circle::Circle(radius=" << radius << ")" << endl;
        this->radius = radius;
    }

    std::unique_ptr<sf::Shape> draw() override {
        cout << "Circle::draw(), area=" << radius * radius * 3.14f << endl;
        return std::make_unique<sf::CircleShape>(radius);
    }

};

class Square final : public Shape {
    float side{};

public:
    explicit Square(const float side = 1.0f) {
        cout << "Square::Square(side=" << side << ")" << endl;
        this->side = side;
    }

    std::unique_ptr<sf::Shape> draw() override {
        cout << "Square::draw(), area=" << side * side << endl;
        return std::make_unique<sf::RectangleShape>(sf::Vector2f(side, side));
    }
};

int main() {
    vector<unique_ptr<Shape>> shapes;

    auto t = make_unique<Circle>(50.0f);
    t->setPosition(200,200);
    t->setRotation(30);
    shapes.push_back(std::move(t));
    auto q = make_unique<Square>(100.0f);
    q->setPosition(400,200);
    q->setRotation(30);
    shapes.push_back(std::move(q));

    sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML Draw v1");

    for (const unique_ptr<Shape>& s : shapes) {
        window.draw(*s->render());
    }

    window.display();

    while (const std::optional event = window.waitEvent())
    {
        if (!event->is<sf::Event::Closed>()) continue;
        window.close();
        return 0;
    }
}
